package firbi.base.com;

import java.util.HashMap;

import junit.framework.TestCase;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;

import com.google.android.maps.GeoPoint;

public class BusStop_Unit_Test extends TestCase {
	
	protected void setUp() {
	}
	
	/**
	 * This method runs the appropriate test when called with a test name.
	 * 
	 * @param testName	The name of the test to run
	 */
	protected void runTest(String testName) {
		Log.i("test", "running test:"+testName);
		if(testName.equalsIgnoreCase("testGettingSetting"))
			testGettingSetting();
		else if(testName.equalsIgnoreCase("testCache"))
			testCache();
		else if(testName.equalsIgnoreCase("testDirectionHelpers"))
			testDirectionHelpers();
	}
	
	protected void tearDown() {
		
	}
	
	/**
	 * This Test tests getting and setting the fields of the BusStop class. It make it easy to add test case data, by
	 * providng an array that you can fill with data in the correct format, tests will be run on a BusStop with the values
	 * that you fill in.
	 * This test trys creating BusStops with all the possible methods of creation and then makes sure that the BusStops
	 * are created correctly and that all of the getter methods are working properly.
	 * This class uses testUpdaters to test that BuStops are properly updated and retrieved from the cache.
	 * This class uses getingAndSettingChecks to make sure that the same values used to create the BusStop are returned
	 * by the getter methods.
	 */
	@MediumTest
	public void testGettingSetting() {
						   //id				agency_id		stopNumber		location								address								direction
		Object[][] tests = {{"0001_10010", 	"0001", 		"10010", 		new GeoPoint(47668578, -122285662), 	"NE 55th St &amp; 39th Ave NE", 	3},
							{"0_0", 		"0", 			"0", 			null, 									null, 								null}};
		
		for(int i = 0; i < tests.length; i++){
			String id = ((String)tests[i][0]);
			String agency_id = ((String)tests[i][1]);
			String stopNumber = ((String)tests[i][2]);
			GeoPoint location = (GeoPoint)tests[i][3];
			String address = (String)tests[i][4];
			Integer direction = (Integer)tests[i][5];
			
			
			BusStop check = null;
			check = BusStop.updateOrCreate(id, stopNumber, location, address, direction);
			gettingSettingChecks(check, i+" (type 1)", id, agency_id, stopNumber, location, address, direction);
			testUpdaters(check, i+" (created with type 1)");
			
			id+="0";
			stopNumber+="0";
			
			HashMap attrs = new HashMap();
			attrs.put("id", id);
			attrs.put("stopNumber", stopNumber);
			attrs.put("location", location);
			attrs.put("address", address);
			attrs.put("direction", direction);
			check = BusStop.updateOrCreate(attrs);
			gettingSettingChecks(check, i+" (type 2)", id, agency_id, stopNumber, location, address, direction);
			testUpdaters(check, i+" (created with type 2");
		}
	}
	
	/**
	 * This Test tests the cache by making a BusStop with an id that is not recognizable to One Bus Away, it then
	 * calls find(id) with the same id and checks that it gets a valid BusStop back and that it is the same BusStop as
	 * was created in this method to ensure the cache is working.
	 * If the cache was to miss One Bus Away would be queried and because the id we chose is not recognized by One Bus 
	 * Away the query would return an error which should cause an exception to be thrown by FirbiCom which will 
	 * cause the test to fail. 
	 */
	@MediumTest
	public void testCache() {
		String id = "0_-12";
		String stopNumber = "fake stop Number";
		String agency_id = "0";
		GeoPoint p = new GeoPoint(1000, 1000);
		String address = "cache test";
		Integer direction = 0;
		
		BusStop.updateOrCreate(id, stopNumber, p, address, direction);
		BusStop check = BusStop.find("0_-12");
		
		assertNotNull("Cache failed, find(ID) returned null after a BusStop was created with it's id equal to ID", check);
		gettingSettingChecks(check, "Cache Test", id, agency_id, stopNumber, p, address, direction);
	}
	
	/**
	 * This Test tests that the direction helper methods directionValue(String direction) and 
	 * directionDisplay(int direction, int display) work. It does so by trying to convert every direction string constant from
	 * BusStop and convert that into a direction number, it makes sure the number is correct and then it calls directionDisplay to convert
	 * it back to a string and makes sure that the same string that it started with is given back.  
	 */
	@MediumTest
	public void testDirectionHelpers() {
		String[][] direction_strings = {BusStop.NORTH_STRINGS, BusStop.EAST_STRINGS, BusStop.SOUTH_STRINGS, BusStop.WEST_STRINGS, BusStop.NORTHEAST_STRINGS, BusStop.NORTHWEST_STRINGS, BusStop.SOUTHEAST_STRINGS, BusStop.SOUTHWEST_STRINGS};
		for(int i = 0; i < direction_strings.length; i++){
			for(int j = 0; j < direction_strings[i].length; j++){
				String directionstr = direction_strings[i][j];
				
				int directionint = BusStop.directionValue(directionstr);
				assertEquals("TestData "+directionstr+": converting direction from String to int failed!", i, directionint);
				
				String newstr = BusStop.directionDisplay(directionint, j);
				assertTrue("Test Data "+directionint+" ; "+j+": converting direction from int to String failed!", directionstr.equals(newstr));
			}
		}
	}
	
	//make a busstop and then try to update it and make sure old pointers have the new value (do this for all constructor types)
	/**
	 * This method checks that updating a BusStop works, it takes the BusStop passed in and creates new values aside from
	 * id and makes sure that these new values are indeed put into the BusStop. This method restores the object passed in
	 * to its original form when it is done with its tests. Unless any of the original values were null. Then these null values
	 * will be overwritten and not changed back to null.
	 * @param stop	the stop to be checked that updates work
	 * @param iden	a string that identifies this run of the method to be used upon failure (ex "1st set of test data")
	 */
	protected void testUpdaters(BusStop stop, String iden) {
		String id = stop.getId();
		String agency_id = stop.getAgencyId();
		String stopNumber = stop.getStopNumber();
		
		GeoPoint location = (stop.getLocation()!=null)? new GeoPoint(stop.getLocation().getLatitudeE6()+10, stop.getLocation().getLongitudeE6()+10) : new GeoPoint(10000, 10000);
		GeoPoint locationo = stop.getLocation();
		
		String address = ((stop.getAddress()!=null)? stop.getAddress()+"cache test" : "cache test");
		String addresso = stop.getAddress();
		
		Integer direction = ((stop.getDirection()!=null && stop.getDirection()<6)? stop.getDirection() + 1 : 0);
		Integer directiono = stop.getDirection();
		
		
		BusStop check = BusStop.updateOrCreate(id, stopNumber, location, address, direction);
		gettingSettingChecks(check, iden+"(changed with type 1)", id, agency_id, stopNumber, location, address, direction);
		
		HashMap attrs = new HashMap();
		attrs.put("id", id);
		attrs.put("stopNumber", stopNumber);
		attrs.put("location", locationo);
		attrs.put("address", addresso);
		attrs.put("direction", directiono);
		check = BusStop.updateOrCreate(attrs);
		gettingSettingChecks(check, iden+"(changed with type 3)", id, agency_id, stopNumber,  ((locationo==null)? location : locationo) , ((addresso==null)? address : addresso), ((directiono==null)? direction : directiono));
		
	}

	/**
	 * This method makes sure that the values passed in are the same inside check which is the BusStop passed in.
	 * @param check
	 * @param iden
	 * @param id
	 * @param agency_id
	 * @param stopNumber
	 * @param onebusawayid
	 * @param location
	 * @param address
	 * @param direction
	 */
	protected void gettingSettingChecks(BusStop check, String iden, String id, String agency_id, String stopNumber, GeoPoint location, String address, Integer direction) {
		assertTrue("TestData "+iden+": setting and getting id failed!", id.equals(check.getId()));
		if(agency_id!=null)
			assertTrue("TestData "+iden+": agency id inconsistent with id! got:"+check.getAgencyId()+" expected:"+agency_id, agency_id.equals(check.getAgencyId()));
		if(stopNumber!=null)
			assertTrue("TestData "+iden+": stop number inconsistent with id! got:"+check.getStopNumber()+" expected:"+stopNumber, stopNumber.equals(check.getStopNumber()));
		assertEquals("TestData "+iden+": setting and getting location failed for latitude!", ((location!=null)? location.getLatitudeE6() : null), ((check.getLocation()!=null)? check.getLocation().getLatitudeE6() : null));
		assertEquals("TestData "+iden+": setting and getting location failed for longitude!", ((location!=null)? location.getLongitudeE6() : null), ((check.getLocation()!=null)? check.getLocation().getLongitudeE6() : null));
		assertTrue("TestData "+iden+": setting and getting address failed! got:"+check.getAddress()+" expected:"+address, ((check.getAddress()!=null)? check.getAddress().equals(address) : address==null));
		assertEquals("TestData "+iden+": setting and getting direction failed!", ((direction!=null)? direction.intValue() : null), ((check.getDirection()!=null)? check.getDirection().intValue() : null));
	}
	
	
	
		
	
	
}
